ICTSC2019 二次予選 問題解説: Welcome to Nginxのページを表示したい!

問題文

あなたはローカルネットワーク上にwebサーバを構築し、IPv6アドレスを使用してwebページに接続できるようにセットアップをしています。
webページへはhttp://nginx.icttoracon.netでアクセスできるようにしたいです。

nginxのホストには、すでにnginxのパッケージをインストール済みです。
CSR1000Vとnginxのホストには固定でIPv6アドレスを割り当てました。
クライアント(VNC Server)にIPv6アドレスが自動設定されるように、CSR1000VにはSLAACの設定を行いました。

しかし、クライアント(VNC Server)のブラウザからhttp://nginx.icttoracon.netにアクセスしてもWelcome to Nginxのページを表示させることができません。
このトラブルを解決し、Welcome to Nginxのページを表示させてください。

クライアントが増えても自動でアクセスできるよう、設定変更はCSR1000Vとnginxホストのみとしてください。
DNSサーバはCSR1000Vを使用します。
各ノードにはssh/telnet用にIPv4アドレスが設定されていますので必要に応じて使用してください。
予選終了後に実環境で採点されるので、スコアサーバでの解答は不要です。

file

接続情報

HostProtocolIPv4 addressUser/Pass
CSR1000Vtelnet192.168.0.1admin/admin
nginxssh192.168.1.2admin/admin

ゴール

VNCサーバのブラウザからhttp://nginx.icttoracon.netでWelcome to Nginxのサイトが表示されること
上記のアクセスがIPv6で行われていること
(恒久的な設定でなくても構わない)

問題解説

本問題には3つの原因があります。
順を追って調べてみましょう。

疎通性確認

まずはクライアントマシンからnginxホストまでIPv6で疎通性があるか確認してみます。
簡単な確認ではありますが、トラブル原因のレイヤをある程度限定できます。

ubuntu@ICTSC-VNC:~$ ping fc01::2 -c 4
PING fc01::2(fc01::2) 56 data bytes
64 bytes from fc01::2: icmp_seq=1 ttl=63 time=0.887 ms
64 bytes from fc01::2: icmp_seq=2 ttl=63 time=0.607 ms
64 bytes from fc01::2: icmp_seq=3 ttl=63 time=0.802 ms
64 bytes from fc01::2: icmp_seq=4 ttl=63 time=0.699 ms

--- fc01::2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3040ms
rtt min/avg/max/mdev = 0.607/0.748/0.887/0.110 ms

コマンドの結果から本問題は初期状態でIPv6の疎通性があることが確認できます。

名前解決

名前解決ができるかどうか試してみましょう。
ドメイン名からIPv6アドレスを取得するにはAAAAレコードを参照します。
例としてAAAAレコードを取得するコマンドを以下に示します。

ubuntu@ICTSC-VNC:~$ dig nginx.icttoracon.net AAAA

; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> nginx.icttoracon.net AAAA
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 40684
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;nginx.icttoracon.net.        IN  AAAA

;; Query time: 89 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Wed Dec 04 22:46:46 JST 2019
;; MSG SIZE  rcvd: 49
ubuntu@ICTSC-VNC:~$

AAAAレコードは取得できていません。
問題文でDNSサーバはCSRとされていますが、クライアントはどこを参照しているのでしょうか。

ubuntu@ICTSC-VNC:~$ cat /etc/resolv.conf | grep -v "^#"

nameserver 127.0.0.53
options edns0
search localdomain
ubuntu@ICTSC-VNC:~$ cat /run/systemd/resolve/resolv.conf | grep -v "^#"

nameserver 133.242.0.3
nameserver 133.242.0.4
search localdomain
ubuntu@ICTSC-VNC:~$ 

IPv4でDNSサーバを受け取っているようですが、CSRのIPアドレスではありません。
1つ目の原因はDNSサーバ(CSR)が参照できていないことです。

問題文からクライアントの設定変更ではなくルータの設定変更で対応する方針であることがわかります。
クライアントの設定とCSRの設定を確認すると、クライアントのIPv6アドレスはRAを用いた自動設定であることがわかります。
ただしDNSサーバのアドレスが配布されていません。
RAでIPv6アドレスが設定されている場合は、以下の2つの方法でDNSサーバを配布することができます。

  • ステートレスDHCPv6
  • RAを用いたDNS配布(RFC8106)

例としてRAのみでDNSの配布を行います。
IOS-XEのコマンドリファレンスを参照すると、以下の設定でDNSの配布が行えそうです。

csr1000v#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
csr1000v(config)#int gi 1
csr1000v(config-if)#ipv6 nd ra dns server fc00::1

クライアントで確認してみます。

ubuntu@ICTSC-VNC:~$ cat /run/systemd/resolve/resolv.conf | grep -v "^#"

nameserver 133.242.0.3
nameserver 133.242.0.4
nameserver fc00::1
search localdomain
ubuntu@ICTSC-VNC:~$ dig nginx.icttoracon.net AAAA

; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> nginx.icttoracon.net AAAA
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35863
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;nginx.icttoracon.net.        IN  AAAA

;; ANSWER SECTION:
nginx.icttoracon.net.    10  IN  AAAA    fc01::2

;; Query time: 12 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Wed Dec 04 22:51:49 JST 2019
;; MSG SIZE  rcvd: 77

ubuntu@ICTSC-VNC:~$

DNSサーバとしてfc00::1が設定され、AAAAレコードが正しく参照できています。

nginx設定

IPv6の疎通性があり、名前解決も行えているので一旦クライアントの作業を終え、nginxホストを確認してみます。
まずは80ポートの使用状況を確認してみます。

[admin@nginx ~]$ sudo lsof -i:80
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1421  root    6u  IPv4   9815      0t0  TCP *:http (LISTEN)
nginx   1422 nginx    6u  IPv4   9815      0t0  TCP *:http (LISTEN)

typeを見るとIPv4となっており、nginxがIPv6アドレスで待ち受けていないことがわかります。
2つ目の原因はnginxはIPv6アドレスで待ち受けていないことです。
nginxがIPv6アドレスで待ち受けるよう、設定を変更します。

server {
    listen       80;
+   listen       [::]:80;
    server_name  localhost;

--- snip ---
[admin@nginx ~]$ sudo nginx -s reload
[admin@nginx ~]$ sudo nginx -s reload
[admin@nginx ~]$ sudo lsof -i:80
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1421  root    6u  IPv4   9815      0t0  TCP *:http (LISTEN)
nginx   1421  root   10u  IPv6  10932      0t0  TCP *:http (LISTEN)
nginx   1540 nginx    6u  IPv4   9815      0t0  TCP *:http (LISTEN)
nginx   1540 nginx   10u  IPv6  10932      0t0  TCP *:http (LISTEN)

フィルタリング設定

nginxがIPv6で待ち受ける状態となりました。
しかしまだクライアントからアクセスができません。
nginxホストのディストリビューションを確認してみます。

[admin@nginx ~]$ ls /etc | grep release
centos-release
redhat-release
system-release
system-release-cpe
[admin@nginx ~]$ cat /etc/centos-release 
CentOS release 6.10 (Final)
[admin@nginx ~]$

CentOS6.10であるため、フィルタリングはiptablesで行っていると予想されます。
iptablesのルールを確認してみましょう。

[admin@nginx ~]$ sudo iptables -L INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED 
ACCEPT     icmp --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:http 
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited 

一見すると問題が無いように見えますが、クライアントはWelcome to Nginxのページにアクセスできません。
それもそのはず、iptablesはIPv4のフィルタリング設定だからです。
実は初期状態からIPv4で80ポートは許可されており、クライアントはIPv4を用いてWelcome to Nginxのページを表示させることはできてました。

IPv6のフィルタリングはip6tableで行います。
ip6tableのルールを確認すると、80ポートのアクセスを許可しているルールが無いことがわかります。

[admin@nginx ~]$ sudo ip6tables -L INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all      anywhere             anywhere            state RELATED,ESTABLISHED 
ACCEPT     ipv6-icmp    anywhere             anywhere            
ACCEPT     all      anywhere             anywhere            
ACCEPT     udp      anywhere             fe80::/64           state NEW udp dpt:dhcpv6-client 
ACCEPT     tcp      anywhere             anywhere            state NEW tcp dpt:ssh 
REJECT     all      anywhere             anywhere            reject-with icmp6-adm-prohibited 

3つ目の原因はIPv6の80ポートが拒否されていることです。
問題文には恒久的な設定ではなくて構わないとしか記載されていないので、80ポートを許可する方法か、プロセスを停止する方法があります。
問題としてはどちらで行ってもいいですが、望ましいのは80ポートを許可する方法です。
ip6tablesで80ポートを許可します。

[admin@nginx ~]$ sudo ip6tables -I INPUT 6 -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
[admin@nginx ~]$ sudo ip6tables -I INPUT 6 -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
[admin@nginx ~]$ sudo ip6tables -L INPUT
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all      anywhere             anywhere            state RELATED,ESTABLISHED 
ACCEPT     ipv6-icmp    anywhere             anywhere            
ACCEPT     all      anywhere             anywhere            
ACCEPT     udp      anywhere             fe80::/64           state NEW udp dpt:dhcpv6-client 
ACCEPT     tcp      anywhere             anywhere            state NEW tcp dpt:ssh 
ACCEPT     tcp      anywhere             anywhere            state NEW tcp dpt:http 
REJECT     all      anywhere             anywhere            reject-with icmp6-adm-prohibited 

クライアントでアクセスしてみると、Welcome to Nginxのページが表示されます。